package com.niiwoo.civet.account.service.local.openAccount2.service;

import com.alibaba.fastjson.JSON;
import com.niiwoo.civet.account.constant.AccountRegisterErrorCode;
import com.niiwoo.civet.account.dao.entity.AccountBase;
import com.niiwoo.civet.account.dao.entity.OpenAccountRecord;
import com.niiwoo.civet.account.enums.*;
import com.niiwoo.civet.account.service.local.openAccount2.dto.AccountInfo;
import com.niiwoo.civet.account.service.local.openAccount2.dto.CreateRequest;
import com.niiwoo.civet.account.service.local.openAccount2.dto.OpenAccountEvent;
import com.niiwoo.civet.account.service.local.openAccount2.dto.QueryUpdateRequest;
import com.niiwoo.civet.account.service.local.openAccount2.dto.UpdateRequest;
import com.niiwoo.civet.account.service.local.openAccount2.dto.UpdateResponse;
import com.niiwoo.civet.account.service.local.openAccount2.type.VoidTypeable;
import com.niiwoo.tripod.base.component.PrivacyMasks;
import com.niiwoo.tripod.base.exception.VerifyFailedException;
import com.niiwoo.tripod.lanmao.component.LanMaoDirectService;
import com.niiwoo.tripod.lanmao.component.LanMaoSequence;
import com.niiwoo.tripod.lanmao.enums.AuditStatusEnum;
import com.niiwoo.tripod.lanmao.enums.UserRoleEnum;
import com.niiwoo.tripod.lanmao.request.QueryUserInformationRequest;
import com.niiwoo.tripod.lanmao.response.LanMaoGatewayDTO;
import com.niiwoo.tripod.lanmao.response.QueryUserInformationResponse;
import com.niiwoo.tripod.provider.exception.BizException;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.function.Supplier;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;

@Slf4j
@Component
public class QueryOpenAccountService extends AbstractOpenAccountService<Void> implements VoidTypeable {

    @Autowired
    LanMaoDirectService lanMaoDirectService;

    @Autowired
    LanMaoSequence lanMaoSequence;

    @Autowired
    PrivacyMasks privacyMasks;


    @Override
    public LanMaoGatewayDTO create(CreateRequest request) {
        throw new UnsupportedOperationException("不支持的操作");
    }

    @Override
    protected void innerCreateParamValid(CreateRequest request) {
        throw new UnsupportedOperationException("不支持的操作");
    }

    @Override
    protected void innerCreateRecordValid(CreateRequest request, List<OpenAccountRecord> recordList) {
        throw new UnsupportedOperationException("不支持的操作");
    }

    @Override
    protected AccountInfo innerUpdateAccountInfo(OpenAccountRecord record, Void order, UpdateRequest request) {
        throw new UnsupportedOperationException("不支持的操作");
    }

    @Transactional(isolation = Isolation.READ_COMMITTED, propagation= Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public <T> T doInTransaction(Supplier<T> s) {
        return s.get();
    }

    @Override
    public UpdateResponse update(UpdateRequest request) {
        log.info("开户查询更新###请求, data={}", JSON.toJSONString(request));
        QueryUpdateRequest queryUpdateRequest = (QueryUpdateRequest) request;
        // 开户记录是否存在
        final OpenAccountRecord recordRead = openAccountRecordMapperExt.selectByUserIdAndRoleAndOrgId(queryUpdateRequest.getUserId(), queryUpdateRequest.getRole(),queryUpdateRequest.getOrgId());
        if (recordRead == null) {
            throw new BizException(AccountRegisterErrorCode.ACCOUNT_REGISTER_RECORD_NOT_EXISTS);
        }
        // 查询懒猫账户信息
        QueryUserInformationResponse queryUserInformationResponse = this.queryLanMaoAccountStatus(recordRead.getAccountNo());
        return ((QueryOpenAccountService)AopContext.currentProxy()).doInTransaction(() -> {
            OpenAccountRecord record = openAccountRecordMapperExt.selectByUserIdAndRoleAndOrgIdForUpdate(queryUpdateRequest.getUserId(), queryUpdateRequest.getRole(),queryUpdateRequest.getOrgId());
            // 开户是否成功
            if (OpenAccountRecordStatusEnum.except(record.getStatus(), OpenAccountRecordStatusEnum.SUCCESS)) {
                return this.getUpdateResponse(OpenAccountRecordStatusEnum.SUCCESS);
            }
            // 判断开户状态
            OpenAccountRecordStatusEnum recordStatus = this.judgeRecordStatusByLanmaoResponse(queryUserInformationResponse, record);
            // 状态相同，直接返回
            if (recordStatus.getValue().equals(record.getStatus())) {
                return this.getUpdateResponse(recordStatus);
            }
            // 更新开户记录
            OpenAccountRecord updateRecord = new OpenAccountRecord();
            updateRecord.setId(record.getId());
            updateRecord.setStatus(recordStatus.getValue());
            updateRecord.setSuccessTime(recordStatus == OpenAccountRecordStatusEnum.SUCCESS ? new Date() : null); // 成功时间
            updateRecord.setGroupAccountNo(queryUserInformationResponse.getGroupAccountNo()); // 集团账户编号
            boolean recordUpdateResult = openAccountRecordMapperExt.updateStatusById(updateRecord) > 0;
            log.info("开户查询更新###开户记录更新###data={}, result={}", JSON.toJSONString(updateRecord), recordUpdateResult);
            // 开户方式
            OpenAccountWayEnum openAccountWay = OpenAccountWayEnum.of(record.getOpenAccountWay());
            // 审核通过, 修改账户信息
            if (recordStatus == OpenAccountRecordStatusEnum.SUCCESS) {
                AccountInfo accountInfo = new AccountInfo();
                accountInfo.setAccountNo(record.getAccountNo());
                accountInfo.setRole(record.getAccountRole());
                accountInfo.setUserId(record.getUserId());
                accountInfo.setName(queryUserInformationResponse.getName());
                accountInfo.setIdCardNo(privacyMasks.encryptPrivacy(queryUserInformationResponse.getIdCardNo().toUpperCase()));
                accountInfo.setBankCardNo(privacyMasks.encryptPrivacy(queryUserInformationResponse.getBankcardNo()));
                accountInfo.setBankCardMobileNo(privacyMasks.encryptPrivacy(queryUserInformationResponse.getMobile()));
                accountInfo.setBankCode(queryUserInformationResponse.getBankcode().getCode());
                accountInfo.setAuthList(queryUserInformationResponse.getAuthlist());
                accountInfo.setIsUpdateBankCard(openAccountWay.getMajor() != OpenAccountMajorWay.GROUP_ACCOUNT_CORRELATE);
                accountInfo.setOrgId(queryUpdateRequest.getOrgId());
                accountInfo.setIsShowBill(isNiiWooAccount(record.getOrgId())? AccountBaseIsShowBillEnum.YES.getValue():AccountBaseIsShowBillEnum.NO.getValue());
                switch (queryUserInformationResponse.getUserType()) {
                    case PERSONAL: {
                        accountInfo.setAccountType(AccountTypeEnum.PERSONAL);
                    }
                    break;
                    case ORGANIZATION: {
                        accountInfo.setAccountType(AccountTypeEnum.ENTERPRISE);
                    }
                    break;
                    default: {
                        log.error("未知用户类型: {}", queryUserInformationResponse.getUserType());
                        throw new BizException("SYS9999");
                    }
                }
                Optional<AccountBase> accountBaseOptional = Optional.ofNullable(accountInfoComposite.getAccount(record.getUserId(), UserRoleEnum.enumOf(record.getAccountRole()),queryUpdateRequest.getOrgId()));
                boolean accountUpdateResult;
                // 存在则更新
                if (accountBaseOptional.isPresent()) {
                    accountUpdateResult = accountInfoComposite.update(accountInfo);
                    // 不存在新增
                } else {
                    accountUpdateResult = accountInfoComposite.save(accountInfo);
                }
                log.info("开户查询更新###账户信息更新###data={}, result={}", JSON.toJSONString(accountInfo), accountUpdateResult);
            }
            // 触发监听事件，用于开户后置处理
            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
                @Override
                public void afterCommit() {
                    super.afterCommit();
                    OpenAccountEvent event = new OpenAccountEvent();
                    record.setStatus(recordStatus.getValue());
                    record.setSuccessTime(updateRecord.getSuccessTime());
                    record.setGroupAccountNo(updateRecord.getGroupAccountNo());
                    event.setRecord(record);
                    event.setErrorCode(request.getErrorCode());
                    event.setErrorMessage(request.getErrorMessage());
                    openAccountListeners.onNotify(event);
                }
            });
            // 返回响应
            log.info("开户查询更新###结果, status={}", recordStatus);
            return this.getUpdateResponse(recordStatus);
        });
    }

    private OpenAccountRecordStatusEnum judgeRecordStatusByLanmaoResponse(QueryUserInformationResponse response, OpenAccountRecord record) {
        OpenAccountRecordStatusEnum currentStatus = OpenAccountRecordStatusEnum.of(record.getStatus());
        // 请求没有成功
        if (!response.isSuccess()) {
            // 存管账户是否存在, 如果不存在且开户记录过期，返回超时状态, 否则返回原状态
            if ("100009".equals(StringUtils.defaultIfBlank(response.getErrorCode(), "")) && isRecordExpire(record.getLastRequestTime())) {
                return OpenAccountRecordStatusEnum.EXPIRED;
            }
            return currentStatus;
        }
        // 迁移导入会员状态=false
        if (!response.getIsImportUserActivate()) {
            // 开户记过过期则返回超时状态, 否则返回原状态
            if (isRecordExpire(record.getLastRequestTime())) {
                return OpenAccountRecordStatusEnum.EXPIRED;
            }
            return currentStatus;
        }
        switch (response.getAuditStatus()) {
            // 审核通过， 账户相关数据审核通过，可以写库，但不一定表示用户可用（还需要判断账户激活状态）
            case PASSED:
                return OpenAccountRecordStatusEnum.SUCCESS;
            // 拒绝，暂时针对企业用户
            case REFUSED:
                return OpenAccountRecordStatusEnum.AUDIT_REJECT;
            // 审核中，暂时针对企业用户
            case AUDIT:
                return OpenAccountRecordStatusEnum.AUDITING;
            // 退回，暂时针对企业用户
            case BACK:
                return OpenAccountRecordStatusEnum.AUDIT_RETURN;
            default: {
                log.error("未知审核类型, accountNo={}, auditStatus={}", response.getPlatformUserNo(), response.getAuditStatus());
                throw new BizException("SYS9999");
            }
        }
    }

    /**
     * 开户记录是否过期
     */
    private boolean isRecordExpire(Date lastRequestDate) {
        // 参数有有效时间 10min, 存管网关页面有效时间 10min, 存管网关处理 5min = 25min
        return System.currentTimeMillis() - lastRequestDate.getTime() > 25L * 60L * 1000L;
    }

    /**
     * 查询懒猫账户状态
     */
    private QueryUserInformationResponse queryLanMaoAccountStatus(String accountNo) {
        QueryUserInformationRequest request = new QueryUserInformationRequest();
        request.setPlatformUserNo(accountNo);
        request.setRequestNo(lanMaoSequence.getRequestNo());
        QueryUserInformationResponse response;
        try {
            log.info("懒猫接口###查询用户信息接口###request={}", JSON.toJSONString(request));
            response = lanMaoDirectService.queryUserInformation(request).get();
            log.info("懒猫接口###查询用户信息接口###response={}", JSON.toJSONString(response));
            return response;
        } catch (ExecutionException e) {
            if (e.getCause() != null && e.getCause() instanceof VerifyFailedException) {
                log.error(String.format("懒猫接口###查询用户信息接口###验签失败, requestNo=%s,  exceptionMessage=%s", request.getRequestNo(), e.getMessage()), e);
                throw new BizException(AccountRegisterErrorCode.LANMAO_QUERY_EXCEPTION);
            } else {
                // 未知异常
                log.error(String.format("懒猫接口###查询用户信息接口###未知异常1， requestNo=%s, exceptionMessage=%s", request.getRequestNo(), e.getMessage()), e);
                throw new BizException(AccountRegisterErrorCode.LANMAO_QUERY_EXCEPTION);
            }
        } catch (Exception e) {
            // 未知异常
            log.error(String.format("懒猫接口###查询用户信息接口###未知异常2， requestNo=%s, exceptionMessage=%s", request.getRequestNo(), e.getMessage()), e);
            throw new BizException(AccountRegisterErrorCode.LANMAO_QUERY_EXCEPTION);
        }
    }

}
